<!-- 资产状态 -->
<template>
  <div class="dashboard-editor-container">
    <div>
      <div style="display:flex;justify-content:space-between;">
        <partitionTree :nodeData="nodeData" :expandArray="expandArray" :addTemplate="false" :defaultExpandAll="false"
          @handleNodeClick="handleNodeClick" ref="partitionTree" @toggleVisibility="toggleVisibility">
        </partitionTree>
        <div :style="{ width: containerWidth }" class="box"
          style="background:#fff;padding: 16px;border: 1px solid #ddd;border-radius: 4px;box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);">
          <connsearch ref="connsearch" :formOptions="formOptions" @search="search" @reset="reset">
            <!-- <el-button type="warning" size="small" @click="restart_Device(false)">批量远程操作</el-button> -->
          </connsearch>
          <el-table stripe border :data="tableData" style="width: 100%; margin-top: 15px" ref="table">
            <el-table-column label="序号" width="80" type="index"
              :index='(index) => { return (index + 1) + (pageNum - 1) * pageSize }'> </el-table-column>
            <el-table-column label="部门" show-overflow-tooltip prop="Department" width="120px"></el-table-column>
            <el-table-column label="资产名称" show-overflow-tooltip prop="DeviceName" width="160px"></el-table-column>
            <el-table-column label="使用者" show-overflow-tooltip prop="UserName" width="120px"></el-table-column>
            <el-table-column label="操作系统" prop="DeviceClass" show-overflow-tooltip></el-table-column>
            <el-table-column label="资产类型" prop="DeviceType" show-overflow-tooltip></el-table-column>
            <el-table-column label="在线状态" prop="StatusChangeTime" width="160" show-overflow-tooltip>
              <template slot-scope="{row}">
                <span>
                  <span style="color:#67C23A" v-if="row.Status === 1" type="success">在线</span>
                  <span style="color:#F56C6C" v-if="row.Status !== 1" type="danger">离线</span>
                  <span v-if="!row.LastReportStatusTime || !row.StatusChangeTime">--初始化</span>
                  <span v-else-if="row.StatusChangeTime_redo">--{{ row.StatusChangeTime_redo }}</span>
                </span>
              </template>
            </el-table-column>
            <el-table-column label="运行时长" prop="KeepRunningTime" show-overflow-tooltip />
            <!-- <el-table-column label="今日事件" prop="TodayEventCount"   show-overflow-tooltip /> -->
            <el-table-column label="操作" width="235" fixed="right">
              <template slot="header" slot-scope="scope">
                <el-button size="mini" type="warning" @click="restart_Device(false)">批量远程操作</el-button>
              </template>
              <template slot-scope="scope">
                <el-button type="primary" size="mini" @click="LookDetails(scope.row)">详情</el-button>
                <!-- <el-button type="primary" size="mini" @click="LookTactics(scope.row)">策略</el-button> -->
                <el-button :type="scope.row.Status === 1 ? 'warning' : 'info'" size="mini"
                  :disabled="scope.row.Status !== 1" @click="operateDevice(scope.row)">远程操作</el-button>
                <el-button type="success" size="mini" @click="LookLog(scope.row)">日志</el-button>
              </template>
            </el-table-column>
          </el-table>
          <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page=pageNum
            :page-size=pageSize background layout="total, prev, pager, sizes, next, jumper" :total="total">
          </el-pagination>
        </div>
      </div>
    </div>
    <el-dialog v-el-drag-dialog :fullscreen="dialogFull" title="远程操作" :close-on-click-modal="false" @close="choseNode = {}"
      :visible.sync="dialogDeviceVisible" width="1000px">
      <template slot="title">
        <div class="avue-crud__dialog__header">
          <span class="el-dialog__title">
            远程操作
          </span>
          <div class="avue-crud__dialog__menu" @click="dialogFull ? dialogFull = false : dialogFull = true">
            <i class="el-icon-full-screen" v-if="dialogFull == false" />
            <i class="el-icon-copy-document" v-else />
          </div>
        </div>
      </template>
      <span style="display:flex;margin-bottom:15px;justify-content: center;width:100%;">
        <span style="display: flex;justify-content: center;align-items: center;">远程命令：</span>
        <div style="display:flex;flex:1">
          <el-select v-model="selectedOption" placeholder="请选择操作" @change="handleSelectChange(selectedOption)">
            <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
          </el-select>
          <el-input v-if="show_shell" type="text" maxlength="200" clearable placeholder="请输入具体指令" v-model="ShellCmd"
            style="margin-left:10px;flex:1">
            <el-button @click="editShell" slot="append" icon="el-icon-edit" title="编辑指令"></el-button>
          </el-input>
        </div>
      </span>
      <tree-transfer :openAll="true" :title="['待选择', '已选择']" :from_data='fromData' :to_data='toData'
        :defaultProps="{ label: 'Name', value: 'ID', children: 'Children' }" ref="myTransfer" :transferOpenNode="true"
        @add-btn='addSelect' @remove-btn='removeSelect' :height="dialogFull ? '640px' : '320px'" filter>
      </tree-transfer>
      <span style="display:flex;margin-top:15px;margin-bottom:24px;justify-content: center;width:100%;">
        <span style="display: flex;justify-content: center;align-items: center;">操作设备：</span>
        <span style="flex: 1;">
          <el-input type="textarea" :autosize="{ minRows: 1, maxRows: 3 }" resize="none" v-model="selectInfo" disabled />
        </span>
      </span>
      <el-divider></el-divider>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submit()">确 定</el-button>
        <el-button type="info" @click="dialogDeviceVisible = false; choseNode = {}">取 消</el-button>
      </span>
    </el-dialog>
    <el-dialog :close-on-click-modal="false" :close-on-press-escape=false title="编辑指令" :visible.sync="editShow"
      v-el-drag-dialog width="40%">
      <el-input type="textarea" :rows="5" placeholder="请输入具体指令" v-model="ShellCmd" maxlength="200" show-word-limit>
      </el-input>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" @click="editShow = false">确 定</el-button>
      </span>
    </el-dialog>

    <RemoteCtrlHistory ref="remoteCtrlHistory"></RemoteCtrlHistory>
  </div>
</template>

<script>
import Cookies from 'js-cookie'
import connsearch from "@/components/connSearch";
import { connrequest } from '@/api/firstPage'
import treeTransfer from 'el-tree-transfer' //注意，这个组件的格式，一定要有id和pid
import { formatDuration, GetDeviceTree } from '@/utils/index'
import elDragDialog from "@/directive/el-drag-dialog";
import partitionTree from "@/components/partitionTree";
import RemoteCtrlHistory from './components/RemoteCtrlHistory.vue';

export default {
  name: 'assetsStatus',
  directives: { elDragDialog, treeTransfer },
  components: {
    partitionTree, connsearch, treeTransfer, RemoteCtrlHistory
  },
  data() {
    let that = this
    return {
      ShellCmd: '',
      editShow: false,
      openAll: false,
      selectInfo: '',
      show_shell: false,
      dialogFull: false,
      pageNum: 1,
      pageSize: 10,
      total: 0,
      containerWidth: 'calc(100% - 275px)',
      tableData: [],
      nodeData: [],
      Action: 1,
      Moder: {},
      choseNode: {},
      dialogTableVisible: false,
      dialogDeviceVisible: false,
      nodeObj: {},
      searchform: {},
      formOptions: [
        {
          col: 8,
          hidden: false,
          label: "在线状态", // label文字
          prop: "Status", // 字段名
          element: "el-select", // 指定elementui组件
          initValue: 0, // 字段初始值,
          placeholder: "请选择在线状态", // elementui组件属性
          options: [
            { label: '全部', value: 0 },
            { label: '在线', value: 1 },
            { label: '离线', value: 2 }
          ],
          events: {
            input(val) {
              that.searchform.Status = val
            }
          }
        },
        {
          col: 8,
          hidden: false,
          label: "排序字段", // label文字
          prop: "Sort_value", // 字段名
          element: "el-select", // 指定elementui组件
          initValue: "Status", // 字段初始值,
          placeholder: "请选择排序字段", // elementui组件属性
          options: [
            { label: '在线状态', value: 'Status' },
            { label: '运行时长', value: 'KeepRunningTime' }
          ],
          events: {
            input(val) {
              that.searchform.Sort_value = val
            }
          }
        },
        {
          col: 8,
          label: "MAC地址", // label文字
          prop: "DeviceMAC", // 字段名
          element: "el-input", // 指定elementui组件
          initValue: "", // 字段初始值,
          placeholder: "请输入MAC地址,支持模糊查询。", // elementui组件属性
          maxlength: 50,
          rules: [], // elementui组件属性
          events: {
            input(val) {
              that.searchform.DeviceMAC = val
            }
          }
        },
      ],
      expandArray: [],
      dialogForm: [],
      fromData: [], // 存储传输的数据
      toData: [],
      lastLevelLeafNodes: [],
      selectedOption: 200, // 设置默认选择第一个选项
      options: [
        { label: '强制关机', value: 200 },
        { label: '强制重启', value: 201 },
        { label: '强制注销', value: 202 },
        { label: '立即执行基线核查', value: 203 },
        { label: '强制刷新硬件和安装软件', value: 204 },
        { label: '执行网络隔离', value: 205 },
        { label: '解除网络隔离', value: 206 },
        { label: '开启远程控制', value: 207 },
        { label: '停止远程控制', value: 208 },
        { label: '发送通知', value: 209 },
        { label: '执行指定命令', value: 210 },
        { label: '卸载客户端', value: 211 },
        { label: '日志上送', value: 212 }
        // { label: '刷新资产实时状态', value: 211 }
      ],
      operatedevice: {},
      schoolMap: ''
    }
  },
  //生命周期 - 创建完成（访问当前this实例）
  created() {
    this.pageSize = (Cookies.get('Zhuoguan_DefaultPageLength') || 10) * 1;

    this.$set(this.searchform, 'Status', 0)
    this.$set(this.searchform, 'Sort_value', 'Status')
    this.getData()
  },
  //生命周期 - 挂载完成（访问DOM元素）
  mounted() {
    this.initData()
    if (this._isMounted) {
      this.onActivated(); // 首次加载时调用
    }
  },
  watch: {
    tableData(val) {
      this.doLayout();
    }
  },
  activated() {
    // 组件激活时触发
    this.onActivated(); // 首次加载时调用
  },
  methods: {
    // 组件激活
    onActivated() {
      if (!this.$route.meta.fromMeta?.isDetail) {
        this.pageSize = (Cookies.get('Zhuoguan_DefaultPageLength') || 10) * 1;

        this.$set(this.searchform, 'Status', 0)
        this.$set(this.searchform, 'Sort_value', 'Status')
        this.getData();
        this.initData();
      }
    },
    async initData(searchobj = {}) {
      try {
        const { DeviceTree } = await GetDeviceTree()
        this.nodeData = DeviceTree
        this.expandArray = [DeviceTree?.[0]?.Name]
      } catch (error) {
        this.$message.error('加载设备树数据失败');
      }
    },
    doLayout() {
      let that = this
      this.$nextTick(() => {
        that.$refs.table.doLayout()
      })
    },
    async GetDeviceTree(childKey = 'Children') {
      let deviceObjList = []
      try {
        // 获取部门数据
        const deptResponse = await connrequest('GetDepartmentDeviceSumTree')
        const departments = deptResponse.Data.Department
        // 获取所有设备数据
        const data = {
          Paging: {
            QueryPageNo: 1,
            QueryPageLength: 100000
          }
        }
        const deviceResponse = await connrequest('GetDevice', data) // 你需要确认是否有这个接口
        const devices = deviceResponse.Data.filter(item => item.Status === 1);
        // 生成树结构
        deviceObjList = this.initDeviceTree(departments, devices)
        return {
          DeviceTree: deviceObjList,
          departments,
          devices
        }
      } catch (error) {
        return { DeviceTree: [], departments, devices }
      }
    },

    async getData(obj) {
      const data = {
        Paging: {
          QueryPageNo: this.pageNum,
          QueryPageLength: this.pageSize
        },
        Filter: {
          DeviceID: this.searchform?.DeviceID || '',
          DeviceMAC: this.searchform?.DeviceMAC || '',
          DeviceName: this.searchform?.DeviceName || '',
          Status: this.searchform.Status,
          OrderBy: this.searchform.Sort_value,
          ...obj
        }
      }
      const res = await connrequest('GetDevice', data)
      res.Data.map(item => {
        item.KeepRunningTime = formatDuration(item.KeepRunningTime)
        const currentTimeStamp = new Date().getTime();
        item.StatusChangeTime_redo = currentTimeStamp / 1000 > item.StatusChangeTime && item.StatusChangeTime != 0 ? formatDuration(currentTimeStamp / 1000 - item.StatusChangeTime) : 0
      })
      this.tableData = res.Data
      this.total = res.Paging.TotalCount
    },
    handleNodeClick(nodeData) {
      this.nodeObj = { DepartmentID: nodeData.data.isDevice ? nodeData.data.DepartmentID : nodeData.data.ID, DeviceUUID: nodeData.data.isDevice ? nodeData.data.DeviceUUID : '' }
      this.getData(this.nodeObj)
    },
    handleSizeChange(pageSize) {
      this.pageSize = pageSize
      this.pageNum = 1
      this.getData(this.nodeObj)
    },
    handleCurrentChange(pageNum) {
      this.pageNum = pageNum
      this.getData(this.nodeObj)
    },
    toggleVisibility(isHidden) {
      if (isHidden)
        this.containerWidth = '100%';
      else
        this.containerWidth = 'calc(100% - 275px)';
    },
    // 搜索
    search(val) {
      this.pageNum = 1
      this.searchform = { ...val }
      this.getData(this.nodeObj)
    },
    // 重置
    reset() {
      this.searchform = {}

      this.nodeObj = {}
      this.$refs.partitionTree.changeHighlightCurrent(null)

      this.$set(this.searchform, 'Status', 0)
      this.$set(this.searchform, 'Sort_value', 'Status')
      this.$refs.connsearch.addInitValue()
      this.getData()
    },
    LookDetails(row) {
      this.activeTab = 'tab1'
      this.dialogForm = { ...row }
      this.$router.push({ path: '/realTimeTraffic/assetDetails' });
      sessionStorage.setItem('detailStatus', JSON.stringify(this.dialogForm))
    },
    async LookTactics(row) {
      this.activeTab = 'tab1'
      this.dialogForm = { ...row }
      this.$router.push({ path: '/realTimeTraffic/tacticsDetails' });
      sessionStorage.setItem('detailStatus', JSON.stringify(this.dialogForm))
    },
    operateDevice(row) {
      this.operatedevice = { ...row }
      this.choseNode = {  ...row  }
      this.restart_Device(true)
    },
    // 获取所有最后一层叶子节点
    getLastLevelLeafNodes(nodeList) {
      const leafNodes = [];
      for (const node of nodeList) {
        if (node.Children && node.Children.length > 0) {
          // 递归处理子节点，并合并结果
          leafNodes.push(...this.getLastLevelLeafNodes(node.Children));
        } else {
          // 叶子节点，直接添加
          leafNodes.push(node);
        }
      }
      return leafNodes;
    },
    async submit() {
      const leafNodes = this.getLastLevelLeafNodes(this.toData);
      const result_info = leafNodes.map(item => ({
        DeviceUUID: item.DeviceUUID || '',
        DeviceName: item.DeviceName || '',
        Action: this.selectedOption,
        ShellCmd: this.selectedOption === 209 || this.selectedOption === 210 ? this.ShellCmd : ''
      }));
      const selectData = result_info;
      if (selectData.length === 0) {
        this.$message.info('请选择需要远程操作的资产')
        return
      }
      if ((this.selectedOption === 209 || this.selectedOption === 210) && this.ShellCmd === '') {
        this.$message.info('请输入具体指令')
        return
      }
      const data = {
        Data: [
          ...selectData
        ]
      }
      this.$confirm('远程指令可能会导致设备侧异常，请在管理人员指导下执行。请谨慎使用。确认要对选择的设备下发远程操作指令吗？', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(async () => {
        const res = await connrequest('CreateRemoteCtrl', data)
        if (res.Status.StatusCode === 0) {
          this.$message.success('操作成功')
          this.dialogDeviceVisible = false
          this.getData()
        }
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消操作'
        });
      });
    },
    cleanEmptyChildren(tree) {
      if (!Array.isArray(tree)) return [];
      return tree
      .map(node => {
          const newNode = { ...node };
          // 如果 Children 是数组，递归处理
          if (Array.isArray(newNode.Children)) {
            newNode.Children = this.cleanEmptyChildren(newNode.Children);
          }
          const noChildren =
            !Array.isArray(newNode.Children) || newNode.Children.length === 0;
          const noDeviceUUID = !newNode.DeviceUUID;
          // ❗满足删除条件：无有效 Children 且无 DeviceUUID
          if (noChildren && noDeviceUUID) {
            return null; // 删除整个节点
          }
          // 否则保留节点（可删除空 Children 字段以干净显示）
          if (noChildren) {
            delete newNode.Children;
          }
          // 如果是已经选中的节点，删除
          if (node.DeviceUUID && node.DeviceUUID === this?.choseNode?.DeviceUUID) {
            return null; // 删除整个节点
          }
          
          return newNode;
        })
        .filter(node => node !== null); // 移除需要删除的节点
    },
    async restart_Device(control) {
      this.$set(this, 'openAll', control)
      this.toData = []
      this.selectInfo = ''
      this.selectedOption = 200
      this.ShellCmd = ''
      this.show_shell = false
      this.dialogDeviceVisible = true
      const { DeviceTree } = await this.GetDeviceTree()
      this.fromData = this.cleanEmptyChildren(DeviceTree)
      if (control) {
        this.toData.push(this.findParentPaths(DeviceTree, [this.operatedevice.DeviceUUID]))
        this.selectInfo = this.operatedevice.DeviceName
      }
    },
    initDeviceTree(departments, devices, childKey = 'Children') {
      let deviceObjList = []
      // 创建部门映射表
      const departmentMap = new Map();
      const departmentClones = departments.map(dept => ({
        ...dept,
        id: dept.ID,
        pid: dept.ParentID,
        [childKey]: []
      }));
      // 建立父子关系
      departmentClones.forEach(dept => {
        departmentMap.set(dept.ID, dept);
        if (dept.ParentID === 0) {
          deviceObjList.push(dept);
        } else {
          const parent = departmentMap.get(dept.ParentID);
          parent && parent[childKey].push(dept);
        }
      });
      // 将设备挂载到对应部门
      devices.forEach(device => {
        const dept = departmentMap.get(device.DepartmentID);
        if (dept) {
          dept[childKey].push({
            ...device,
            ID: device.DeviceUUID,
            id: device.DeviceUUID,
            pid: device.DepartmentID,
            Name: device.DeviceName || device.DeviceCode || '未命名设备',
            [childKey]: null,
            leaf: false,
            isDevice: true
          });
        }
      });
      return deviceObjList
    },
    findParentPaths(tree, targetIds) {
      // 辅助函数，递归查找单个 id 的路径
      function searchNode(nodes, id, path = []) {
        for (let node of nodes) {
          // 将当前节点加入路径
          const currentPath = [...path, {
            ...node,
            Name: node.Name || node.DeviceName,
            id: node.id,
            pid: node.pid,
            ...(node.Children ? { Children: node.Children } : {})
          }];
          // 如果当前节点是要找的节点，返回路径
          if (node.id === id) {
            return currentPath;
          }
          // 如果有子节点，继续递归查找
          if (node.Children && node.Children.length > 0) {
            const result = searchNode(node.Children, id, currentPath);
            if (result) {
              return result;
            }
          }
        }
        return null;
      }
      // 存储所有找到的路径
      const allPaths = targetIds
        .map(id => searchNode(tree, id))
        .filter(path => path !== null); // 过滤掉未找到的路径
      // 如果没有找到任何路径，返回 null 或空结构
      if (allPaths.length === 0) {
        return null;
      }
      // 合并路径到树状结构
      function mergePaths(paths) {
        // 创建一个映射，用于存储 id 对应的节点
        const nodeMap = new Map();
        // 遍历所有路径
        for (let path of paths) {
          let parent = null;
          for (let node of path) {
            const nodeId = node.id;
            if (!nodeMap.has(nodeId)) {
              // 创建新节点，清理 Children（稍后重新构建）
              const newNode = {
                ...node,
                Name: node.Name,
                id: nodeId,
                pid: node.pid,
                Children: []
              };
              nodeMap.set(nodeId, newNode);
            }
            // 建立父子关系
            if (parent) {
              const parentNode = nodeMap.get(parent.id);
              // 避免重复添加子节点
              if (!parentNode.Children.some(child => child.id === nodeId)) {
                parentNode.Children.push(nodeMap.get(nodeId));
              }
            }
            parent = node;
          }
        }
        // 找到根节点（pid 为 0 或最顶层节点）
        const rootNodes = Array.from(nodeMap.values()).filter(node =>
          node.pid === 0 || !Array.from(nodeMap.values()).some(n => n.Children.includes(node))
        );
        // 如果只有一个根节点，返回它
        if (rootNodes.length === 1) {
          return rootNodes[0];
        }
        // 如果有多个根节点，返回包含它们的数组
        return rootNodes;
      }
      return mergePaths(allPaths);
    },
    getAllDeviceNames(tree) {
      const deviceNames = [];
      // 递归遍历树
      function traverse(nodes) {
        if (!nodes || !Array.isArray(nodes)) return;
        for (let node of nodes) {
          // 如果节点有 DeviceName，添加到结果数组
          if (node.DeviceName) {
            deviceNames.push(node.DeviceName);
          }
          // 如果有 Children，继续递归
          if (node.Children) {
            traverse(node.Children);
          }
        }
      }
      // 从根节点开始遍历
      traverse(tree);
      return deviceNames.join('、');
    },
    handleSelectChange(val) {
      if (val === 209 || val === 210) this.show_shell = true
      else this.show_shell = false
    },
    addSelect(fromData, toData, obj) {
      this.selectInfo = ''
      this.selectInfo = this.getAllDeviceNames(toData)
    },
    removeSelect(fromData, toData, obj) {
      this.selectInfo = ''
      this.selectInfo = this.getAllDeviceNames(toData)
    },
    editShell() {
      this.editShow = true
    },
    LookLog(row) {
      this.$refs.remoteCtrlHistory.open(row)
    }
  }
};
</script>
<style scoped>
.box {
  background-color: lightblue;
  transition: width 0.5s;
  /* 添加过渡动画 */
}

.wl-transfer .transfer-title,
.wl-transfer ::v-deep .transfer-title {
  font-size: 14px !important;
  margin: 0 !important;
}

::v-deep .el-descriptions__header {
  margin-bottom: 5px;
}

/*  dialog*/
.el-dialog__header {
  padding: 15px 20px 15px;
}

.el-dialog__headerbtn {
  top: 15px;
}

/* dialog header */
.avue-crud__dialog__header {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-align: center;
  -ms-flex-align: center;
  align-items: center;
  -webkit-box-pack: justify;
  -ms-flex-pack: justify;
  justify-content: space-between;
}

.el-dialog__title {
  color: rgba(0, 0, 0, .85);
  font-weight: 500;
  word-wrap: break-word;
}

.avue-crud__dialog__menu {
  padding-right: 35px;
  float: left;
}

.avue-crud__dialog__menu i {
  color: white;
  font-size: 15px;
}

.el-icon-full-screen {
  cursor: pointer;
}

.el-icon-full-screen:before {
  content: "\e719";
}

.el-icon-copy-document {
  cursor: pointer;
}
</style>
